Skip to content

feat(analyze): implement noInlineStyles#9534

Merged
Netail merged 3 commits intobiomejs:mainfrom
Netail:feat/no-inline-styles
Mar 22, 2026
Merged

feat(analyze): implement noInlineStyles#9534
Netail merged 3 commits intobiomejs:mainfrom
Netail:feat/no-inline-styles

Conversation

@Netail
Copy link
Member

@Netail Netail commented Mar 17, 2026

Summary

Added the nursery rule NoInlineStyles which disallows the usage of style prop in HTML and JSX files.

Closes #9062

In favour of #9319 & #9146 (inactive)

Test Plan

Unit tests

Docs

@changeset-bot
Copy link

changeset-bot bot commented Mar 17, 2026

🦋 Changeset detected

Latest commit: b487334

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 13 packages
Name Type
@biomejs/biome Patch
@biomejs/cli-win32-x64 Patch
@biomejs/cli-win32-arm64 Patch
@biomejs/cli-darwin-x64 Patch
@biomejs/cli-darwin-arm64 Patch
@biomejs/cli-linux-x64 Patch
@biomejs/cli-linux-arm64 Patch
@biomejs/cli-linux-x64-musl Patch
@biomejs/cli-linux-arm64-musl Patch
@biomejs/wasm-web Patch
@biomejs/wasm-bundler Patch
@biomejs/wasm-nodejs Patch
@biomejs/backend-jsonrpc Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions bot added A-CLI Area: CLI A-Project Area: project A-Linter Area: linter L-JavaScript Language: JavaScript and super languages A-Diagnostic Area: diagnostocis L-HTML Language: HTML and super languages labels Mar 17, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 17, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6bf5bb3a-5659-4388-8a12-d8c961d6871f

📥 Commits

Reviewing files that changed from the base of the PR and between 9d0a07e and b487334.

⛔ Files ignored due to path filters (6)
  • crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs is excluded by !**/migrate/eslint_any_rule_to_biome.rs and included by **
  • crates/biome_configuration/src/analyzer/linter/rules.rs is excluded by !**/rules.rs and included by **
  • crates/biome_configuration/src/generated/linter_options_check.rs is excluded by !**/generated/**, !**/generated/** and included by **
  • crates/biome_diagnostics_categories/src/categories.rs is excluded by !**/categories.rs and included by **
  • packages/@biomejs/backend-jsonrpc/src/workspace.ts is excluded by !**/backend-jsonrpc/src/workspace.ts and included by **
  • packages/@biomejs/biome/configuration_schema.json is excluded by !**/configuration_schema.json and included by **
📒 Files selected for processing (1)
  • crates/biome_rule_options/src/lib.rs

Walkthrough

Adds a patch-level changeset noInlineStyles. Implements a new nursery lint noInlineStyles for HTML and JS/JSX that detects inline styles (HTML style attributes, JSX style props, and React.createElement style props), emits diagnostics, and offers an unsafe autofix that removes the inline style. Adds NoInlineStylesOptions and exports its module. Adds test fixtures (valid/invalid) for HTML, Astro, Svelte, Vue and JSX. Adds is_custom_component helper for React create-element handling.

Suggested reviewers

  • ematipico
  • dyc3
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: implementing the noInlineStyles rule for the linter.
Description check ✅ Passed The description adequately explains what was added (nursery rule NoInlineStyles), references the closed issue, and outlines the test plan.
Linked Issues check ✅ Passed The PR implements the noInlineStyles rule across HTML and JSX as required by issue #9062, detecting inline styles and providing autoremediation.
Out of Scope Changes check ✅ Passed All changes are scoped to implementing the noInlineStyles rule: new rule implementations, test files, options, and supporting utilities.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

You can customize the high-level summary generated by CodeRabbit.

Configure the reviews.high_level_summary_instructions setting to provide custom instructions for generating the high-level summary.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
.changeset/strong-mirrors-attend.md (1)

5-5: Consider adding an inline code example of invalid usage.

As per coding guidelines, changesets for new lint rules should include an example of an invalid case.

📝 Suggested addition
-Added the nursery rule [`noInlineStyles`](https://biomejs.dev/linter/rules/no-inline-styles/). The rule disallows the use of inline `style` attributes in HTML and the `style` prop in JSX, including `React.createElement` calls. Inline styles make code harder to maintain and can interfere with Content Security Policy.
+Added the nursery rule [`noInlineStyles`](https://biomejs.dev/linter/rules/no-inline-styles/). The rule disallows the use of inline `style` attributes in HTML and the `style` prop in JSX, including `React.createElement` calls. Inline styles make code harder to maintain and can interfere with Content Security Policy.
+
+```jsx
+// Invalid
+<div style={{ color: "red" }}>Error</div>
+```
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.changeset/strong-mirrors-attend.md at line 5, Add an invalid usage example
to the changeset: update .changeset/strong-mirrors-attend.md to include a fenced
code block labeled "jsx" that shows an inline style being used (e.g., a JSX
element with a style prop like a div using style={{ color: "red" }}) and mark it
as "// Invalid" so readers see a concrete disallowed example for the new
noInlineStyles rule.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/biome_js_analyze/src/lint/nursery/no_inline_styles.rs`:
- Around line 82-86: The branch handling NoInlineStylesQuery::JsCallExpression
currently constructs NoInlineStylesState::JsxAttribute for React.createElement
calls; change it to use the ReactProp variant instead: in the JsCallExpression
arm (where you call ctx.model() and find_style_attribute(call_expression,
model)?), detect that the call_expression is a React.createElement invocation
and return NoInlineStylesState::ReactProp(property_member.range()) rather than
JsxAttribute(property_member.range()); keep using find_style_attribute and the
existing property_member.range() to locate the node but switch the variant to
ReactProp so createElement props are classified correctly.

---

Nitpick comments:
In @.changeset/strong-mirrors-attend.md:
- Line 5: Add an invalid usage example to the changeset: update
.changeset/strong-mirrors-attend.md to include a fenced code block labeled "jsx"
that shows an inline style being used (e.g., a JSX element with a style prop
like a div using style={{ color: "red" }}) and mark it as "// Invalid" so
readers see a concrete disallowed example for the new noInlineStyles rule.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d3d69339-5874-4ec8-8464-640b6ce457fd

📥 Commits

Reviewing files that changed from the base of the PR and between 4b64145 and 7d4c009.

⛔ Files ignored due to path filters (10)
  • crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs is excluded by !**/migrate/eslint_any_rule_to_biome.rs and included by **
  • crates/biome_configuration/src/analyzer/linter/rules.rs is excluded by !**/rules.rs and included by **
  • crates/biome_configuration/src/generated/linter_options_check.rs is excluded by !**/generated/**, !**/generated/** and included by **
  • crates/biome_diagnostics_categories/src/categories.rs is excluded by !**/categories.rs and included by **
  • crates/biome_html_analyze/tests/specs/nursery/noInlineStyles/invalid.html.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/nursery/noInlineStyles/valid.html.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noInlineStyles/invalid.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noInlineStyles/valid.jsx.snap is excluded by !**/*.snap and included by **
  • packages/@biomejs/backend-jsonrpc/src/workspace.ts is excluded by !**/backend-jsonrpc/src/workspace.ts and included by **
  • packages/@biomejs/biome/configuration_schema.json is excluded by !**/configuration_schema.json and included by **
📒 Files selected for processing (9)
  • .changeset/strong-mirrors-attend.md
  • crates/biome_html_analyze/src/lint/nursery/no_inline_styles.rs
  • crates/biome_html_analyze/tests/specs/nursery/noInlineStyles/invalid.html
  • crates/biome_html_analyze/tests/specs/nursery/noInlineStyles/valid.html
  • crates/biome_js_analyze/src/lint/nursery/no_inline_styles.rs
  • crates/biome_js_analyze/tests/specs/nursery/noInlineStyles/invalid.jsx
  • crates/biome_js_analyze/tests/specs/nursery/noInlineStyles/valid.jsx
  • crates/biome_rule_options/src/lib.rs
  • crates/biome_rule_options/src/no_inline_styles.rs

@codspeed-hq
Copy link

codspeed-hq bot commented Mar 17, 2026

Merging this PR will not alter performance

✅ 58 untouched benchmarks
⏩ 156 skipped benchmarks1


Comparing Netail:feat/no-inline-styles (b487334) with main (97b80a8)

Open in CodSpeed

Footnotes

  1. 156 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@Netail Netail marked this pull request as draft March 17, 2026 23:36
Co-authored-by: MCMXC <16797721+mcmxcdev@users.noreply.github.com>
@Netail Netail force-pushed the feat/no-inline-styles branch from 7d4c009 to 688da2d Compare March 17, 2026 23:48
@Netail Netail marked this pull request as ready for review March 17, 2026 23:49
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (3)
crates/biome_rule_options/src/no_inline_styles.rs (1)

1-6: Add rustdoc documentation for the options struct.

As per coding guidelines, rule options should have inline rustdoc documentation explaining what the options control. Even for an empty struct, a brief description helps.

📝 Suggested fix
 use biome_deserialize_macros::{Deserializable, Merge};
 use serde::{Deserialize, Serialize};
+
+/// Options for the `noInlineStyles` rule.
 #[derive(Default, Clone, Debug, Deserialize, Deserializable, Merge, Eq, PartialEq, Serialize)]
 #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
 #[serde(rename_all = "camelCase", deny_unknown_fields, default)]
 pub struct NoInlineStylesOptions {}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_rule_options/src/no_inline_styles.rs` around lines 1 - 6, Add a
rustdoc comment for the NoInlineStylesOptions struct describing what the options
control (even if empty) by placing a /// doc comment immediately above the pub
struct NoInlineStylesOptions {} definition; reference the struct name
NoInlineStylesOptions and briefly explain that these options configure the "no
inline styles" rule (e.g., purpose and that there are currently no configurable
fields).
.changeset/strong-mirrors-attend.md (1)

1-5: Consider adding an invalid code example.

Based on learnings, changesets for new lint rules should include an example of an invalid case. A brief JSX snippet would help users quickly understand what the rule catches.

📝 Suggested addition
 ---
 "@biomejs/biome": patch
 ---

 Added the nursery rule [`noInlineStyles`](https://biomejs.dev/linter/rules/no-inline-styles/). The rule disallows the use of inline `style` attributes in HTML and the `style` prop in JSX, including `React.createElement` calls. Inline styles make code harder to maintain and can interfere with Content Security Policy.
+
+```jsx
+// Invalid
+<div style={{ color: "red" }}>Error</div>
+```
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.changeset/strong-mirrors-attend.md around lines 1 - 5, Add an explicit
"Invalid" example to the changeset description for the new nursery rule
`noInlineStyles` so users can quickly see what the rule catches; update the
`.changeset/strong-mirrors-attend.md` content to include a short JSX snippet
under a clear "Invalid" heading (e.g., show a JSX element using the `style` prop
such as a `div` with `style={{ color: "red" }}`) and ensure it is fenced as code
for readability and consistency with other changesets.
crates/biome_js_analyze/src/lint/nursery/no_inline_styles.rs (1)

52-58: Consider adding sources metadata.

This rule is ported from html-eslint. As per coding guidelines, rules derived from other linters should use the sources metadata to attribute the original source.

📝 Suggested fix
     pub NoInlineStyles {
         version: "next",
         name: "noInlineStyles",
         language: "js",
         recommended: false,
         fix_kind: FixKind::Unsafe,
+        sources: &[RuleSource::EslintHtmlEslint("no-inline-styles")],
     }

You'll also need to import RuleSource from biome_analyze.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_js_analyze/src/lint/nursery/no_inline_styles.rs` around lines 52
- 58, The NoInlineStyles rule metadata is missing the required sources
attribution; import RuleSource from biome_analyze and add a sources field to the
rule initializer (e.g., sources: vec![RuleSource::HtmlEslint]) alongside the
existing version/name/language/recommended/fix_kind values to attribute the
original html-eslint source.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In @.changeset/strong-mirrors-attend.md:
- Around line 1-5: Add an explicit "Invalid" example to the changeset
description for the new nursery rule `noInlineStyles` so users can quickly see
what the rule catches; update the `.changeset/strong-mirrors-attend.md` content
to include a short JSX snippet under a clear "Invalid" heading (e.g., show a JSX
element using the `style` prop such as a `div` with `style={{ color: "red" }}`)
and ensure it is fenced as code for readability and consistency with other
changesets.

In `@crates/biome_js_analyze/src/lint/nursery/no_inline_styles.rs`:
- Around line 52-58: The NoInlineStyles rule metadata is missing the required
sources attribution; import RuleSource from biome_analyze and add a sources
field to the rule initializer (e.g., sources: vec![RuleSource::HtmlEslint])
alongside the existing version/name/language/recommended/fix_kind values to
attribute the original html-eslint source.

In `@crates/biome_rule_options/src/no_inline_styles.rs`:
- Around line 1-6: Add a rustdoc comment for the NoInlineStylesOptions struct
describing what the options control (even if empty) by placing a /// doc comment
immediately above the pub struct NoInlineStylesOptions {} definition; reference
the struct name NoInlineStylesOptions and briefly explain that these options
configure the "no inline styles" rule (e.g., purpose and that there are
currently no configurable fields).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 51cba0cc-9c93-4eef-8120-5da716b72b57

📥 Commits

Reviewing files that changed from the base of the PR and between 7d4c009 and 688da2d.

⛔ Files ignored due to path filters (10)
  • crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs is excluded by !**/migrate/eslint_any_rule_to_biome.rs and included by **
  • crates/biome_configuration/src/analyzer/linter/rules.rs is excluded by !**/rules.rs and included by **
  • crates/biome_configuration/src/generated/linter_options_check.rs is excluded by !**/generated/**, !**/generated/** and included by **
  • crates/biome_diagnostics_categories/src/categories.rs is excluded by !**/categories.rs and included by **
  • crates/biome_html_analyze/tests/specs/nursery/noInlineStyles/invalid.html.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/nursery/noInlineStyles/valid.html.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noInlineStyles/invalid.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noInlineStyles/valid.jsx.snap is excluded by !**/*.snap and included by **
  • packages/@biomejs/backend-jsonrpc/src/workspace.ts is excluded by !**/backend-jsonrpc/src/workspace.ts and included by **
  • packages/@biomejs/biome/configuration_schema.json is excluded by !**/configuration_schema.json and included by **
📒 Files selected for processing (9)
  • .changeset/strong-mirrors-attend.md
  • crates/biome_html_analyze/src/lint/nursery/no_inline_styles.rs
  • crates/biome_html_analyze/tests/specs/nursery/noInlineStyles/invalid.html
  • crates/biome_html_analyze/tests/specs/nursery/noInlineStyles/valid.html
  • crates/biome_js_analyze/src/lint/nursery/no_inline_styles.rs
  • crates/biome_js_analyze/tests/specs/nursery/noInlineStyles/invalid.jsx
  • crates/biome_js_analyze/tests/specs/nursery/noInlineStyles/valid.jsx
  • crates/biome_rule_options/src/lib.rs
  • crates/biome_rule_options/src/no_inline_styles.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • crates/biome_js_analyze/tests/specs/nursery/noInlineStyles/valid.jsx
  • crates/biome_html_analyze/src/lint/nursery/no_inline_styles.rs

Copy link
Member

@ematipico ematipico left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This new pr didn't address of my previous comments.

Not enough tests, diagnostics don't follow the rule pillars, docs to adjust

Comment on lines +67 to +75
let node = ctx.query();

let name = node.name().ok()?;
let value_token = name.value_token().ok()?;
if value_token.text_trimmed().to_lowercase_cow() == "style" {
return Some(());
}

None
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We must distinguish between components and normal tags.

Components shouldn't be triggered

Comment on lines +85 to +89
"Avoid using the "<Emphasis>"style"</Emphasis>" attribute. Prefer external CSS classes instead of inline styles."
},
)
.note(markup! {
"Inline styles make code harder to maintain, reduce reusability, and can prevent effective use of a strict Content Security Policy."
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's follow the rule pillars, the exact order:

  • error
  • why
  • solution

Plus, the "Prefer.." phrase goes in conflict with the action

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tweaked the diagnostic a bit, but unsure about it 🤔

@ematipico
Copy link
Member

I closed the inactive PRs

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
crates/biome_js_analyze/src/react.rs (1)

99-109: Consider scoping is_custom_component to pub(crate).

This helper reads like internal analyser plumbing; keeping it crate-scoped avoids unintentionally expanding the public API surface.

Suggested tweak
-    pub fn is_custom_component(&self) -> bool {
+    pub(crate) fn is_custom_component(&self) -> bool {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_js_analyze/src/react.rs` around lines 99 - 109, Change the
visibility of the helper function is_custom_component from pub to pub(crate) to
keep this internal analyser plumbing out of the public API; locate the
is_custom_component method on the React node (the function that checks
element_type -> as_any_js_expression -> as_any_js_literal_expression ->
as_js_string_literal_expression) and make it crate-scoped (pub(crate)) instead
of public.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/biome_js_analyze/src/lint/nursery/no_inline_styles.rs`:
- Around line 89-90: The message string "Unexpected
\"<Emphasis>\"style\"</Emphasis>\" attribute." is inaccurate for object member
(React.createElement) hits; update the wording wherever that literal appears
(e.g., the message constant or message construction in no_inline_styles.rs) to
"Unexpected \"<Emphasis>\"style\"</Emphasis>\" attribute or property." so it
covers both DOM attributes and JS object properties; ensure you change every
occurrence (including the second instance corresponding to the other hit) so
messages are consistent.
- Around line 146-153: The loop over props.members() uses the try operator (`?`)
on each step (member.ok()?, as_js_property_object_member()?, name().ok()?,
as_js_literal_member_name()?, value().ok()?) which causes the whole function to
return early when encountering non-property members (spreads/computed), missing
later style props; change those `?` uses to fallible checks that continue the
loop on None/Err (e.g., use if let/let Some(...) or match and continue) so you
only skip the offending member instead of exiting the function, and keep the
early return only when is_style_value(&value) is true (return
Some(property_member.clone())).

---

Nitpick comments:
In `@crates/biome_js_analyze/src/react.rs`:
- Around line 99-109: Change the visibility of the helper function
is_custom_component from pub to pub(crate) to keep this internal analyser
plumbing out of the public API; locate the is_custom_component method on the
React node (the function that checks element_type -> as_any_js_expression ->
as_any_js_literal_expression -> as_js_string_literal_expression) and make it
crate-scoped (pub(crate)) instead of public.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d613f9e8-00aa-4535-801a-5715cd310882

📥 Commits

Reviewing files that changed from the base of the PR and between 688da2d and b463e46.

⛔ Files ignored due to path filters (10)
  • crates/biome_html_analyze/tests/specs/nursery/noInlineStyles/astro/invalid.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/nursery/noInlineStyles/astro/valid.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/nursery/noInlineStyles/invalid.html.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/nursery/noInlineStyles/svelte/invalid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/nursery/noInlineStyles/svelte/valid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/nursery/noInlineStyles/valid.html.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/nursery/noInlineStyles/vue/invalid.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/nursery/noInlineStyles/vue/valid.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noInlineStyles/invalid.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noInlineStyles/valid.jsx.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (13)
  • crates/biome_html_analyze/src/lint/nursery/no_inline_styles.rs
  • crates/biome_html_analyze/tests/specs/nursery/noInlineStyles/astro/invalid.astro
  • crates/biome_html_analyze/tests/specs/nursery/noInlineStyles/astro/valid.astro
  • crates/biome_html_analyze/tests/specs/nursery/noInlineStyles/invalid.html
  • crates/biome_html_analyze/tests/specs/nursery/noInlineStyles/svelte/invalid.svelte
  • crates/biome_html_analyze/tests/specs/nursery/noInlineStyles/svelte/valid.svelte
  • crates/biome_html_analyze/tests/specs/nursery/noInlineStyles/valid.html
  • crates/biome_html_analyze/tests/specs/nursery/noInlineStyles/vue/invalid.vue
  • crates/biome_html_analyze/tests/specs/nursery/noInlineStyles/vue/valid.vue
  • crates/biome_js_analyze/src/lint/nursery/no_inline_styles.rs
  • crates/biome_js_analyze/src/react.rs
  • crates/biome_js_analyze/tests/specs/nursery/noInlineStyles/invalid.jsx
  • crates/biome_js_analyze/tests/specs/nursery/noInlineStyles/valid.jsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/biome_js_analyze/tests/specs/nursery/noInlineStyles/invalid.jsx

Comment on lines +89 to +90
"Unexpected "<Emphasis>"style"</Emphasis>" attribute."
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Message wording is inaccurate for React.createElement cases.

When the hit is an object member, “attribute” is misleading; “attribute or property” would match both paths.

Also applies to: 118-118

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_js_analyze/src/lint/nursery/no_inline_styles.rs` around lines 89
- 90, The message string "Unexpected \"<Emphasis>\"style\"</Emphasis>\"
attribute." is inaccurate for object member (React.createElement) hits; update
the wording wherever that literal appears (e.g., the message constant or message
construction in no_inline_styles.rs) to "Unexpected
\"<Emphasis>\"style\"</Emphasis>\" attribute or property." so it covers both DOM
attributes and JS object properties; ensure you change every occurrence
(including the second instance corresponding to the other hit) so messages are
consistent.

@Netail Netail force-pushed the feat/no-inline-styles branch from b463e46 to 9d0a07e Compare March 18, 2026 13:00
@Netail Netail requested a review from ematipico March 18, 2026 13:07
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
crates/biome_html_analyze/src/lint/nursery/no_inline_styles.rs (1)

116-119: Consider using ? instead of unwrap() for defensive coding.

While action() is only invoked after run() returns Some, the unwrap() calls assume the attribute still exists. Using ? would be more defensive against potential AST inconsistencies.

🛡️ Proposed fix
         match node {
             AnyHtmlElement::HtmlElement(element) => {
                 let opening = element.opening_element().ok()?;
-                mutation.remove_node(find_style_attribute(opening.attributes()).unwrap())
+                mutation.remove_node(find_style_attribute(opening.attributes())?)
             }
-            AnyHtmlElement::HtmlSelfClosingElement(self_closing_element) => mutation
-                .remove_node(find_style_attribute(self_closing_element.attributes()).unwrap()),
+            AnyHtmlElement::HtmlSelfClosingElement(self_closing_element) => {
+                mutation.remove_node(find_style_attribute(self_closing_element.attributes())?)
+            }
             _ => {}
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_html_analyze/src/lint/nursery/no_inline_styles.rs` around lines
116 - 119, The code currently force-unwraps the optional attribute via
find_style_attribute(...).unwrap() inside the AnyHtmlElement arms (HtmlElement
and HtmlSelfClosingElement), which can panic if the AST changed; replace those
unwrap() calls with the ? operator so the action() helper propagates None
instead of panicking. Concretely, change
mutation.remove_node(find_style_attribute(opening.attributes()).unwrap()) and
the self-closing variant to mutation.remove_node(find_style_attribute(...)?),
and ensure the enclosing action() function signature and return type allow
propagation (i.e., return Option or Result as appropriate) so the ? compiles.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@crates/biome_html_analyze/src/lint/nursery/no_inline_styles.rs`:
- Around line 116-119: The code currently force-unwraps the optional attribute
via find_style_attribute(...).unwrap() inside the AnyHtmlElement arms
(HtmlElement and HtmlSelfClosingElement), which can panic if the AST changed;
replace those unwrap() calls with the ? operator so the action() helper
propagates None instead of panicking. Concretely, change
mutation.remove_node(find_style_attribute(opening.attributes()).unwrap()) and
the self-closing variant to mutation.remove_node(find_style_attribute(...)?),
and ensure the enclosing action() function signature and return type allow
propagation (i.e., return Option or Result as appropriate) so the ? compiles.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 5fcd218b-f0e9-4a40-a14e-8f8fdd186e3f

📥 Commits

Reviewing files that changed from the base of the PR and between b463e46 and 9d0a07e.

⛔ Files ignored due to path filters (10)
  • crates/biome_html_analyze/tests/specs/nursery/noInlineStyles/astro/invalid.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/nursery/noInlineStyles/astro/valid.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/nursery/noInlineStyles/invalid.html.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/nursery/noInlineStyles/svelte/invalid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/nursery/noInlineStyles/svelte/valid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/nursery/noInlineStyles/valid.html.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/nursery/noInlineStyles/vue/invalid.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/nursery/noInlineStyles/vue/valid.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noInlineStyles/invalid.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noInlineStyles/valid.jsx.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (13)
  • crates/biome_html_analyze/src/lint/nursery/no_inline_styles.rs
  • crates/biome_html_analyze/tests/specs/nursery/noInlineStyles/astro/invalid.astro
  • crates/biome_html_analyze/tests/specs/nursery/noInlineStyles/astro/valid.astro
  • crates/biome_html_analyze/tests/specs/nursery/noInlineStyles/invalid.html
  • crates/biome_html_analyze/tests/specs/nursery/noInlineStyles/svelte/invalid.svelte
  • crates/biome_html_analyze/tests/specs/nursery/noInlineStyles/svelte/valid.svelte
  • crates/biome_html_analyze/tests/specs/nursery/noInlineStyles/valid.html
  • crates/biome_html_analyze/tests/specs/nursery/noInlineStyles/vue/invalid.vue
  • crates/biome_html_analyze/tests/specs/nursery/noInlineStyles/vue/valid.vue
  • crates/biome_js_analyze/src/lint/nursery/no_inline_styles.rs
  • crates/biome_js_analyze/src/react.rs
  • crates/biome_js_analyze/tests/specs/nursery/noInlineStyles/invalid.jsx
  • crates/biome_js_analyze/tests/specs/nursery/noInlineStyles/valid.jsx
🚧 Files skipped from review as they are similar to previous changes (4)
  • crates/biome_html_analyze/tests/specs/nursery/noInlineStyles/svelte/valid.svelte
  • crates/biome_js_analyze/src/react.rs
  • crates/biome_html_analyze/tests/specs/nursery/noInlineStyles/vue/valid.vue
  • crates/biome_html_analyze/tests/specs/nursery/noInlineStyles/astro/invalid.astro

Copy link
Member

@ematipico ematipico left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! Merge whenever you want

@Netail Netail merged commit 4d050df into biomejs:main Mar 22, 2026
23 checks passed
@Netail Netail deleted the feat/no-inline-styles branch March 22, 2026 22:16
@github-actions github-actions bot mentioned this pull request Mar 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-CLI Area: CLI A-Diagnostic Area: diagnostocis A-Linter Area: linter A-Project Area: project L-HTML Language: HTML and super languages L-JavaScript Language: JavaScript and super languages

Projects

None yet

Development

Successfully merging this pull request may close these issues.

📎 Port no-inline-styles from html-eslint

2 participants